{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import re\n",
    "from pyvis.network import Network\n",
    "from pyltp import Segmentor, Postagger, Parser, SementicRoleLabeller\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "#对句子进行语义角色标注\n",
    "def parser_main(sentence):\n",
    "    LTP_DIR=\"C:/Users/Administrator/Desktop/ltp_data_v3.4.0\"   #LTP模型文件路径\n",
    "    #实例化Segmentor类的对象\n",
    "    segmentor=Segmentor(os.path.join(LTP_DIR,\"cws.model\"))\n",
    "    #实例化Postagger类的对象\n",
    "    postagger=Postagger(os.path.join(LTP_DIR,\"pos.model\"))\n",
    "    #实例化Parser类的对象\n",
    "    parser=Parser(os.path.join(LTP_DIR,\"parser.model\"))\n",
    "    labeller = SementicRoleLabeller(os.path.join(LTP_DIR,\"pisrl_win.model\"))    #实例化SementicRoleLabeller类的对象\n",
    "    words=list(segmentor.segment(sentence))  #分词\n",
    "    postags=list(postagger.postag(words))    #词性标注\n",
    "    arcs=parser.parse(words,postags)         #依存句法分析\n",
    "    roles=labeller.label(words,postags,arcs) #语义角色标注\n",
    "    roles_dict={key:{sub_key:[sub_key,*value] for sub_key,value in sub_data} for key, sub_data in roles}\n",
    "    return words, postags, arcs, roles_dict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "分词结果： ['苏轼', '是', '宋朝', '的', '著名', '文学家', '，', '黄庭坚', '是', '苏轼', '的', '好', '朋友', '。', '苏轼', '擅长', '写', '词', '，', '而', '黄庭坚', '擅长', '写', '诗', '。', '黄庭坚', '游览', '黄州', '，', '并', '赞叹', '黄山', '之', '美', '。', '黄庭坚', '探望', '苏轼', '，', '并', '一起', '吟诗', '作', '对', '。']\n",
      "语义角色标注结果： {1: {'A0': ['A0', 0, 0], 'A1': ['A1', 2, 5]}, 8: {'A0': ['A0', 7, 7], 'A1': ['A1', 9, 12]}, 15: {'A0': ['A0', 14, 14]}, 16: {'A1': ['A1', 17, 17]}, 21: {'A0': ['A0', 20, 20], 'A1': ['A1', 23, 23]}, 22: {'A1': ['A1', 23, 23]}, 26: {'A0': ['A0', 25, 25], 'A1': ['A1', 27, 27]}, 30: {'DIS': ['DIS', 29, 29], 'A1': ['A1', 31, 33]}, 36: {'A0': ['A0', 35, 35], 'A1': ['A1', 37, 37]}, 41: {'A0': ['A0', 35, 35], 'DIS': ['DIS', 39, 39], 'ADV': ['ADV', 40, 40]}, 42: {'ADV': ['ADV', 40, 40]}}\n"
     ]
    }
   ],
   "source": [
    "text=\"苏轼是宋朝的著名文学家，黄庭坚是苏轼的好朋友。苏轼擅长写词，而黄庭坚擅长写诗。黄庭坚游览黄州，并赞叹黄山之美。黄庭坚探望苏轼，并一起吟诗作对。\"\n",
    "words, postags, arc, roles_dict = parser_main(text)\n",
    "print(\"分词结果：\",words)\n",
    "print(\"语义角色标注结果：\",roles_dict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def ruler(words, postags, roles_dict, role_index):\n",
    "    v=words[role_index]  #提取词索引对应的谓词\n",
    "    #提取词索引对应的语义角色标注\n",
    "    role_info=roles_dict[role_index]\n",
    "    if 'A0'in role_info.keys() and 'A1' in role_info.keys():\n",
    "        #从语义角色标注中提取施事\n",
    "        s = ''.join([words[word_index] for word_index in range(role_info['A0'][1],   role_info['A0'][2]+1) if \n",
    "                     postags[word_index] [0] not in ['w','u','x'] and words[word_index]])\n",
    "                #从语义角色标注中提取施事\n",
    "        o = ''.join([words[word_index] for word_index in range(role_info['A1'][1],   role_info['A1'][2]+1) if \n",
    "                     postags[word_index] [0] not in ['w','u','x'] and words[word_index]])\n",
    "        if s and o:\n",
    "            return '1', [s,v,o]#返回【施事，谓词，受词】形式的三元组\n",
    "    return '4',[]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "def triples_main(text):\n",
    "    #使用正则表达式将文本分割为句子\n",
    "    sentences = [sentence for sentence in re.split(r'[？?！!。；;：:\\n\\r]',text)if sentence]\n",
    "    svos = []\n",
    "    for index, sentence in enumerate(sentences):\n",
    "        words,postags,arcs,roles_dict=parser_main(sentence)\n",
    "        for index in range(len(postags)):\n",
    "            #根据语义角色标注提取三元组\n",
    "            if index in roles_dict:\n",
    "                flag, triple = ruler(words, postags, roles_dict, index)\n",
    "                if flag == '1':\n",
    "                    svos.append(triple)\n",
    "    return svos"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "文本的三元组：svos=[['苏轼', '是', '宋朝著名文学家'], ['黄庭坚', '是', '苏轼好朋友'], ['苏轼', '擅长', '写词'], ['黄庭坚', '擅长', '诗'], ['黄庭坚', '游览', '黄州'], ['黄庭坚', '赞叹', '黄山美'], ['黄庭坚', '探望', '苏轼']]\n"
     ]
    }
   ],
   "source": [
    "svos=triples_main(text)\n",
    "print(\"文本的三元组：svos={0}\".format(svos))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "#创建语义网络中的节点\n",
    "def create_node(net, subs1, subs2):\n",
    "    if len(subs1) != 0:\n",
    "        for i in range(len(subs1)):\n",
    "            #调用add_node()方法创建节点\n",
    "            net.add_node(i, label= subs1[i], color=\"blue\")\n",
    "    if len(subs2) !=0:\n",
    "        for i in range(len(subs2)):\n",
    "            net.add_node(1000+i, label = subs2[i], color=\"green\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "def create_node_id_dic(net):   #创建节点标签到节点ID的映射字典\n",
    "    dic_node_id = {}\n",
    "    for i in net.node_ids:    #游历net对象中所有的节点ID\n",
    "        dic_node_id[str(net.node_map[i][\"label\"])] = i\n",
    "    return dic_node_id"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "def create_network(net, kg_list, node_id_dic):   #添加节点之间的边\n",
    "    for m in range(len(kg_list)):\n",
    "        try:\n",
    "            net.add_edge(node_id_dic[kg_list[m][0]],node_id_dic[kg_list[m][2]], label=kg_list[m][1],color=\"red\",widt=2)  #添加节点之间的边\n",
    "        except AttributeError as e:\n",
    "                print(e,m)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Warning: When  cdn_resources is 'local' jupyter notebook has issues displaying graphics on chrome/safari. Use cdn_resources='in_line' or cdn_resources='remote' if you have issues viewing graphics in a notebook.\n",
      "my_network.html\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "        <iframe\n",
       "            width=\"100%\"\n",
       "            height=\"600px\"\n",
       "            src=\"my_network.html\"\n",
       "            frameborder=\"0\"\n",
       "            allowfullscreen\n",
       "        ></iframe>\n",
       "        "
      ],
      "text/plain": [
       "<IPython.lib.display.IFrame at 0x221558c6eb8>"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#实例化Network类的对象net\n",
    "net = Network(notebook = True, directed = True)\n",
    "subs1 = list(set(sublist[0] for sublist in svos))\n",
    "subs2 = list(set(sublist[2] for sublist in svos))\n",
    "#调用create_node()函数创建语义网络的节点\n",
    "create_node(net,subs1,subs2)\n",
    "#调用create_node_id_dic()函数创建节点标签到节点ID的映射字典\n",
    "dic_node_id = create_node_id_dic(net)\n",
    "#调用create_network()函数添加语义网络中节点之间的边\n",
    "create_network(net, svos, dic_node_id)\n",
    "net.show(\"my_network.html\")   #显示语义网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "def find_similar_semantics(net,node_id_dic,target_node):   #查找与目标词语义相关的词\n",
    "    #查找目标节点的ID\n",
    "    target_node_id = node_id_dic[target_node]\n",
    "    #获取目标节点的所有相邻节点\n",
    "    adjacent_nodes = net.neighbors(target_node_id)\n",
    "    #使用逆字典将相邻节点的ID转换为节点标签\n",
    "    similar_semantics = [node_id_dic_inverse[node_id] for node_id in adjacent_nodes]\n",
    "    return similar_semantics"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "与目标词'苏轼'语义相关的词： ['宋朝著名文学家', '写词']\n"
     ]
    }
   ],
   "source": [
    "#创建一个反向的节点ID字典，以便通过节点ID查找节点标签\n",
    "node_id_dic_inverse = {v: k for k, v in dic_node_id.items()}\n",
    "#查找与目标词“苏轼”语义相关的词\n",
    "similar =find_similar_semantics(net, dic_node_id, '苏轼')\n",
    "print(\"与目标词'苏轼'语义相关的词：\", similar)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
